package top.lixunda.common.utils.alipay;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;
import top.lixunda.commerce.common.core.exception.AppException;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.common.utils.alipay.constant.AlipayConstant;
import top.lixunda.common.utils.alipay.entity.AlipayDefaultParam;
import top.lixunda.common.utils.alipay.entity.AlipayNotifyResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * 支付宝客户端
 *
 * @author lixunda
 * @version time:2020/3/2 10:35
 */
@Slf4j
public class AlipayClientUtils {

    /**
     * 单例模式
     */
    private static volatile AlipayClient alipayClient;

    /**
     * 单例模式，全局参数配置
     *
     * @return AlipayClient
     */
    private static AlipayClient getAlipayClient() {
        if (alipayClient == null) {
            synchronized ((AlipayClientUtils.class)) {
                if (alipayClient == null) {
                    alipayClient = new DefaultAlipayClient(AlipayConstant.URL,
                            AlipayConstant.APP_ID, AlipayConstant.APP_PRIVATE_KEY, AlipayConstant.FORMAT,
                            AlipayConstant.CHARSET, AlipayConstant.ALIPAY_PUBLIC_KEY, AlipayConstant.SIGN_TYPE);
                }
            }
        }
        return alipayClient;
    }

    /**
     * 异步通知消息验签
     *
     * @param request HttpServletRequest
     * @return 是否校验通过，通过返回true，否则返回false
     * @throws AlipayApiException 支付宝校验失败
     */
    public static boolean rsaCheckV1(HttpServletRequest request) throws AlipayApiException {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>(16);
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        // 切记ALIPAY_PUBLIC_KEY是支付宝的公钥，请去open.alipay.com对应应用下查看。
        return AlipaySignature.rsaCheckV1(params, AlipayConstant.ALIPAY_PUBLIC_KEY, AlipayConstant.CHARSET, AlipayConstants.SIGN_TYPE_RSA2);
    }

    /**
     * 调用支付页面进行订单支付
     *
     * @param alipayDefaultParam 支付订单数据
     * @return 返回页面的html
     * @throws IllegalArgumentException 参数错误，参数不能为空
     */
    public static String toPay(AlipayDefaultParam alipayDefaultParam) throws IllegalArgumentException {
        if (ObjectValidators.isEmpty(alipayDefaultParam)) {
            log.error("参数不能为空");
            throw new IllegalArgumentException("参数不能为空");
        }
        log.error(alipayDefaultParam.toString());
        AlipayClient alipayClient = AlipayClientUtils.getAlipayClient();
        //创建API对应的request
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(alipayDefaultParam.getReturnUrl());
        //在公共参数中设置回跳和通知地址
        alipayRequest.setNotifyUrl(alipayDefaultParam.getNotifyUrl());
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(alipayDefaultParam.getOutTradeNo());
        model.setProductCode(alipayDefaultParam.getProductCode());
        model.setSubject(alipayDefaultParam.getSubject());
        model.setBody(alipayDefaultParam.getBody());
        model.setTotalAmount(alipayDefaultParam.getTotalAmount());
        model.setPassbackParams(alipayDefaultParam.getPassbackParams());
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId(alipayDefaultParam.getSysServiceProviderId());
        model.setExtendParams(extendParams);
        //填充业务参数
        alipayRequest.setBizModel(model);
        String form = "";

        try {
            //调用SDK生成表单
            AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest);
            if (response.isSuccess()) {
                form = alipayClient.pageExecute(alipayRequest).getBody();
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return form;
    }

    /**
     * 订单退货
     *
     * @param result 付款通知数据
     */
    public static void tradeRefund(AlipayNotifyResult result,
                                   BiConsumer<AlipayNotifyResult, AlipayTradeRefundResponse> callback) throws AlipayApiException {
        AlipayClient alipayClient = getAlipayClient();
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setTradeNo(result.getTradeNo());
        model.setOutTradeNo(result.getOutTradeNo());
        model.setRefundAmount(result.getTotalAmount());
        model.setRefundReason("正常退款");
        request.setBizModel(model);
        AlipayTradeRefundResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            if (callback != null) {
                callback.accept(result, response);
            }
        } else {
            throw new AppException("调用退款失败: " + response.getMsg());
        }
    }

    /**
     * 将字符串写回前端
     *
     * @param httpResponse HttpServletResponse
     * @param form         字符串
     * @throws IOException IOException
     */
    public static void writeToResponse(HttpServletResponse httpResponse, String form) throws IOException {
        httpResponse.setContentType("text/html;charset=" + AlipayConstant.CHARSET);
        //直接将完整的表单html输出到页面
        httpResponse.getWriter().write(form);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

}
